﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using GPSCrowdSource.Algorithms;

namespace GPSCrowdSource.DataStructures {
  
  /// <summary>
  /// A collection of geo positions by time 
  /// </summary>
  public class TimeSpaceCollection  : IEnumerable<GeoPosition> {

    #region Private
    
    private List<GeoPosition> myList = new List<GeoPosition>();

    private GeoPosition myMeanPos = new GeoPosition(DateTime.MinValue,float.MaxValue,float.MaxValue,float.MaxValue);

    private TimeBin myBin;

    #endregion

    #region Constructors
    /// <summary>
    /// Create the collection with the time bin it refelects.
    /// </summary>
    public TimeSpaceCollection(TimeBin inBin) { myBin = inBin; }
    #endregion

    /// <summary>
    /// Add a position to the list.
    /// </summary>
    public void Add(GeoPosition inPos) {

      lock(myList) {

        if(myMeanPos.Latitude == float.MaxValue)
          myMeanPos.Latitude = inPos.Latitude;
        else
          myMeanPos.Latitude += inPos.Latitude;

        if(myMeanPos.Longitude == float.MaxValue)
          myMeanPos.Longitude = inPos.Longitude;
        else
          myMeanPos.Longitude += inPos.Longitude;
        
        if(myMeanPos.Altitude == float.MaxValue)
          myMeanPos.Altitude = inPos.Altitude;
        else
          myMeanPos.Altitude += inPos.Altitude;
         

        myList.Add(inPos);
        }
      } 

    /// <summary>
    /// Get the mean position value of the bin.
    /// </summary>
    public GeoPosition Mean {
      get {
        double c = myList.Count;
        return new GeoPosition((float)(myMeanPos.Latitude/c),(float)(myMeanPos.Longitude/c),(float)(myMeanPos.Altitude/c));
        }
      }

    /// <summary>
    /// Compute the min/max/ave radius
    /// </summary>
    public Vector3 Radii {
      get {

        double min = double.MaxValue;
        double max = double.MinValue;
        double ave = 0;
        double c = myList.Count;

        lock(myList) {
          GeoPosition mean = Mean;
          for(int i=0;i<myList.Count;i++) {
            double d = GeoUtils.GetDistance(myList[i],mean);
            ave += d;

            if(d < min)
              min = d;
            if(d > max)
              max = d;
            }

          return new Vector3((float)min,(float)max,(float)(ave/c));
          }

        }
      }

    /// <summary>
    /// Get the elemetn at the direct index.
    /// </summary>
    public GeoPosition this[int idx] {
      get {
        return myList[idx];
        }
      }

    /// <summary>
    /// Get the number of elements in this collection.
    /// </summary>
    public int Count { get  { return myList.Count; }}

    /// <summary>
    /// Get the time bin represented by this collection of positions.
    /// </summary>
    public TimeBin Bin { get { return myBin; }}

    #region IEnumerable
    public IEnumerator<GeoPosition> GetEnumerator() {
      return myList.GetEnumerator();
      }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
      return myList.GetEnumerator();
    }
    #endregion

    }

  }
